using System;
using Microsoft.SPOT;

namespace Robot
{
    /// <summary>
    /// Implements WatchDog timer
    /// </summary>
    class WatchDog
    {
        public delegate void TimeOutHandler();
        public event TimeOutHandler TimeOut;

        System.Threading.Timer timer;
        System.Threading.TimerCallback timerDelegate;
        bool m_running = false;

        /// <summary>
        /// Constructor - Sets up timer
        /// </summary>
        public WatchDog()
        {
            timerDelegate = new System.Threading.TimerCallback(Watch);
            timer = new System.Threading.Timer(timerDelegate, null, System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
        }

        /// <summary>
        /// Stops WatchDog timer
        /// </summary>
        public void Stop()
        {
            timer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
            m_running = false;
        }

        /// <summary>
        /// Starts the watchdog timer
        /// </summary>
        /// <param name="msec">Milliseconds to wait for feeds before timeout</param>
        /// <param name="restart">Restart if already running?</param>
        public void Start(int msec, bool restart)
        {
            if (!m_running || restart)
            {
                m_running = true;
                Feed(msec);
            }
        }

        /// <summary>
        /// Is called when timeout occurs and notifies subscribers.
        /// </summary>
        /// <param name="o"></param>
        void Watch(Object o)
        {
            if (TimeOut != null)
            {
                TimeOut();
            }
            Stop();
        }

        /// <summary>
        /// Feeds the dog so that in won't attack for a while
        /// </summary>
        /// <param name="msec">Milliseconds to allow before next feeding must occur</param>
        public void Feed(int msec)
        {
            if (m_running)
            {
                timer.Change(msec, msec);
            }
        }
    }
}
